//
//  SingleValueCodingContainer.swift
//  MoonKit
//
//  Created by moon on 2019/3/5.
//  Copyright © 2019 moon. All rights reserved.
//

import Foundation

public protocol SingleValueCodingContainer {
	var codingOperation:CodingOperation { get }
	var codingPath: [CodingKey] { get }
	
	/// 编码nil
	///
	/// - throws: `CodingError.invalidValue`: 当前容器不支持编码nil
	mutating func encodeNil() throws

	/// 编码对象到当前容器中
	///
	/// - parameter value: 被编码的对象
	/// - throws: `EncodingError.invalidValue` : 当前容器不支持编码此对象
	mutating func encode<T>(_ value: T) throws where T : Codable
	
	mutating func encode(_ value: Bool) throws
	
	mutating func encode(_ value: String) throws
	
	mutating func encode(_ value: Double) throws
	
	mutating func encode(_ value: Float) throws
	
	mutating func encode(_ value: Int) throws
	
	mutating func encode(_ value: Int8) throws
	
	mutating func encode(_ value: Int16) throws
	
	mutating func encode(_ value: Int32) throws
	
	mutating func encode(_ value: Int64) throws
	
	mutating func encode(_ value: UInt) throws
	
	mutating func encode(_ value: UInt8) throws
	
	mutating func encode(_ value: UInt16) throws
	
	mutating func encode(_ value: UInt32) throws
	
	mutating func encode(_ value: UInt64) throws
	
	/// 解码nil出来
	///
	/// - returns: 是否成功解码nil
	func decodeNil() -> Bool
	
	/// 解码指定类型的对象出来
	///
	/// - parameter type: 对象类型
	/// - returns: 被解码出来的对象
	/// - throws: `CodingError.typeMismatch` : 解码时,类型不符合
	/// - throws: `CodingError.valueNotFound` : 解码出null
	func decode<T>(_ type: T.Type) throws -> T where T : Codable
	
	func decode(_ type: Bool.Type) throws -> Bool
	
	func decode(_ type: String.Type) throws -> String
	
	func decode(_ type: Double.Type) throws -> Double
	
	func decode(_ type: Float.Type) throws -> Float
	
	func decode(_ type: Int.Type) throws -> Int
	
	func decode(_ type: Int8.Type) throws -> Int8
	
	func decode(_ type: Int16.Type) throws -> Int16
	
	func decode(_ type: Int32.Type) throws -> Int32
	
	func decode(_ type: Int64.Type) throws -> Int64
	
	func decode(_ type: UInt.Type) throws -> UInt
	
	func decode(_ type: UInt8.Type) throws -> UInt8
	
	func decode(_ type: UInt16.Type) throws -> UInt16
	
	func decode(_ type: UInt32.Type) throws -> UInt32
	
	func decode(_ type: UInt64.Type) throws -> UInt64
    
    /// 以自身为对象,构造一个Coder出来.编码时,Coder的内容将保存到自身.解码时,Coder的内容为自身
    ///
    /// - Returns: 嵌套的编解码器
    /// - Throws: `CodingError.keyNotFound` : 解码时,key不存在
    mutating func superCoder() throws -> Coder
}


extension SingleValueCodingContainer {
	
	/// 编码对象到当前容器中
	/// 如果T为以下类型:['Bool', 'String', 'Double', 'Float','Int', 'Int8', 'Int16', 'Int32', 'Int64','UInt', 'UInt8', 'UInt16', 'UInt32', 'UInt64'],则会调用具体类型对应的方法,否则调用泛型的T方法
	///
	/// - parameter value: 被编码的对象
	/// - throws: `EncodingError.invalidValue` : 当前容器不支持编码此对象
	public mutating func encodeCodableValue<T:Codable>(_ value: T) throws {
        let t = type(of: value)
        if t == Bool.self {
            try encode(value as! Bool)
        }else if t == String.self {
            try encode(value as! String)
        }else if t == Double.self {
            try encode(value as! Double)
        }else if t == Float.self {
            try encode(value as! Float)
        }else if t == Int.self {
            try encode(value as! Int)
        }else if t == Int8.self {
            try encode(value as! Int8)
        }else if t == Int16.self {
            try encode(value as! Int16)
        }else if t == Int32.self {
            try encode(value as! Int32)
        }else if t == Int64.self {
            try encode(value as! Int64)
        }else if t == UInt.self {
            try encode(value as! UInt)
        }else if t == UInt8.self {
            try encode(value as! UInt8)
        }else if t == UInt16.self {
            try encode(value as! UInt16)
        }else if t == UInt32.self {
            try encode(value as! UInt32)
        }else if t == UInt64.self {
            try encode(value as! UInt64)
        }else{
            try encode(value)
        }
	}
	
	/// 解码指定类型的对象出来
	/// 如果T为以下类型:['Bool', 'String', 'Double', 'Float','Int', 'Int8', 'Int16', 'Int32', 'Int64','UInt', 'UInt8', 'UInt16', 'UInt32', 'UInt64'],则会调用具体类型对应的方法,否则调用泛型的T方法
	///
	/// - parameter type: 对象类型
	/// - returns: 被解码出来的对象
	/// - throws: `CodingError.typeMismatch` : 解码时,类型不符合
	/// - throws: `CodingError.valueNotFound` : 解码出null
	public func decodeCodableValue<T:Codable>(_ type: T.Type) throws -> T {
		switch type {
		case let t as Bool.Type:
			return try decode(t) as! T
		case let t as String.Type:
			return try decode(t) as! T
		case let t as Double.Type:
			return try decode(t) as! T
		case let t as Float.Type:
			return try decode(t) as! T
		case let t as Int.Type:
			return try decode(t) as! T
		case let t as Int8.Type:
			return try decode(t) as! T
		case let t as Int16.Type:
			return try decode(t) as! T
		case let t as Int32.Type:
			return try decode(t) as! T
		case let t as Int64.Type:
			return try decode(t) as! T
		case let t as UInt.Type:
			return try decode(t) as! T
		case let t as UInt8.Type:
			return try decode(t) as! T
		case let t as UInt16.Type:
			return try decode(t) as! T
		case let t as UInt32.Type:
			return try decode(t) as! T
		case let t as UInt64.Type:
			return try decode(t) as! T
		default:
			return try decode(type)
		}
	}
    public func decodeCodableValueIfPresent<T:Codable>(_ type: T.Type) throws -> T? {
        if decodeNil() {
            return nil
        } else {
            return try decodeCodableValue(type)
        }
    }
}
